#include "muduo/net/EventLoopThread.h"
#include "muduo/net/TcpClient.h"

#include "codec.h"
#include "dispatcher.h"

#include "response.pb.h"
#include <memory>
#include <iostream>

using namespace rbmq;
class Client
{
    typedef std::shared_ptr<rbmq::TranslateResponse> TranslateResponsePtr;
    typedef std::shared_ptr<rbmq::AddResponse> AddResponsePtr;

public:
    Client(const std::string &serverip, const int serverport)
        : _latch(1),
          _client(_loopthread.startLoop(), muduo::net::InetAddress(serverip, serverport), "Client"),
          _dispatcher(std::bind(&Client::onUnknownMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)),
          _codec(std::bind(&ProtobufDispatcher::onProtobufMessage, &_dispatcher, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))
    {
        // 为派发器注册方法
        _dispatcher.registerMessageCallback<rbmq::TranslateResponse>(std::bind(&Client::OnTranslate, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
        _dispatcher.registerMessageCallback<rbmq::AddResponse>(std::bind(&Client::OnAdd, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));

        // 设置连接方法
        _client.setConnectionCallback(std::bind(&Client::onConnection, this, std::placeholders::_1));

        // 设置消息处理，协议解析
        _client.setMessageCallback(std::bind(&ProtobufCodec::onMessage, &_codec, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
    }

    void Translate(const std::string &message)
    {
        TranslateRequest req;
        req.set_word(message);
        send(&req);
    }

    void Add(int num1, int num2)
    {
        rbmq::AddRequest req;
        req.set_num1(num1);
        req.set_num2(num2);
        send(&req);
    }
    // 阻塞连接，直到连接成功
    void connect()
    {
        _client.connect();
        _latch.wait(); // 阻塞
    }

    bool send(const google::protobuf::Message *message)
    {
        if (_conn->connected())
        {
            _codec.send(_conn, *message);
            return true;
        }
        return false;
    }

private:
    // 建立连接和断开才调用，唤醒阻塞
    void onConnection(const muduo::net::TcpConnectionPtr &conn)
    {
        if (conn->connected())
        {
            _latch.countDown();
            _conn = conn;
        }
        else
        {
            _conn.reset();
            std::cout << "连接断开" << std::endl;
        }
    }

    void onUnknownMessage(const muduo::net::TcpConnectionPtr &conn, const MessagePtr &message, muduo::Timestamp)
    {
        std::cout << "onUnknownMessage: " << message->GetTypeName();
        conn->shutdown();
    }

    void OnTranslate(const muduo::net::TcpConnectionPtr &conn, const TranslateResponsePtr &message, muduo::Timestamp t)
    {
        std::cout << "Translate: " << message->trans() << std::endl;
    }

    void OnAdd(const muduo::net::TcpConnectionPtr &conn, const AddResponsePtr &message, muduo::Timestamp t)
    {
        std::cout << "ADD: " << message->ret() << std::endl;
    }

private:
    muduo::CountDownLatch _latch;
    muduo::net::EventLoopThread _loopthread;
    muduo::net::TcpConnectionPtr _conn;
    muduo::net::TcpClient _client;

    ProtobufDispatcher _dispatcher; // 事件派发器
    ProtobufCodec _codec;           // 协议处理器
};

int main()
{
    Client client("127.0.0.1", 8088);
    client.connect();

    client.Add(10, 30);
    client.Translate("word");

    sleep(1);
    return 0;
}